\chapter{Architektura aplikacji}
\label{chap:etap3-architektura}

\section{Podział na moduły}
Na rysunku~\ref{fig:etap3-architektura} przedstawiono podział aplikacji na moduły o~różnym zakresie odpowiedzialności. Od strony użytkownika końcowego widoczna jest strona WWW. Pozwala ona na wywołanie za pomocą odpowiedniego formularza zapytania dot. przejazdów zgodnych z~oczekiwaniami użytkownika. Dane zapytania przekazywane są do modułu kontrolera (\textit{Controller}), który zarządza tym co i~w~jakiej sytuacji ma zostać wykonane. Kontroler wywołuje metody serwisu (\textit{Service}). Natomiast rolą serwisu jest przede wszystkim komunikacja z~grafową bazą danych Neo4j.

\begin{figure}
	\includegraphics{figures/architektura.pdf}
	\caption{Architektura aplikacji}
	\label{fig:etap3-architektura}
\end{figure}\textsc{}

\section{Strona WWW}

\subsection{Budowa}
Strona www oparta jest o dokument JSP, zawierający stronę HTML wraz ze skryptami \mbox{JavaScript}. Korzysta z dodatkowych dwóch bibliotek:
\begin{enumerate}
	\item jquery -- lekka biblioteka programistyczna ułatwiająca korzystanie z JavaScript,
	\item jsDatePick -- darmowa (dostępna pod GPL\footnote{\burl{http://opensource.org/licenses/gpl-3.0.html}}) biblioteka JavaScript umożliwiająca. korzystanie z kalendarza
\end{enumerate}

Cała zawartość strony opiera się o dokument html kodowany w formacie UTF-8 mający określoną z góry strukturę podzieloną i schierarchizowaną za pomocą znaczników div. Podczas wykonywania zapytania do serwera (z użyciem biblioteki jquery) wykorzystuje się funkcję ajax. Do zapytania w postaci URL dołączane są niezbędne parametry pobrane z pól formularza dokumentu html. Przy poprawnym wykonaniu zapytania, odpowiedź zwrotna (kodowana również w formacie UTF-8) na podstawie otrzymanych danych modyfikuje stronę html poprzez edycję obiektów DOM.
Kod JavaScript podzielony został na szereg funkcji:
\begin{enumerate}
	\item init - funkcja wykonywana po załadowaniu dokumentu, inicjuje m.in. interaktywny kalendarz
	\item performSearch - funkcja pobierająca wprowadzone przez użytkownika dane i wysyłająca AJAXowe zapytanie do serwera. Specyfikuje ona również procedurę obsługi odpowiedzi,
	\item formatDate - funkcja pomocnicza, konwertująca znacznik czasu na sformatowany do obecnych potrzeb string reprezentujący chwilę czasową,
	\item changeDebug - funkcja zmieniająca stan globalnej flagi debug, pomagająca w debugowaniu kodu strony www,
	\item resetInput - funkcja wywoływana poprzez naciśnięcie przycisku przez użytkownika oraz tuż po załadowaniu dokumentu. Inicjuje pierwotne wartości formularza domyślnymi danymi (m.in. aktualnym czasem).
\end{enumerate}
Do strony załączone są niezbędne grafiki takie jak tło, czy elementy interaktywnego kalendarza.

\subsection{Korzystanie}

Aby skorzystać ze strony (oraz całego serwisu) należy wpisać w pole adresu przeglądarki internetowej adres komputera na którym działa serwer aplikacji. Serwer nasłuchuje na porcie 80, więc nie trzeba go dodatkowo specyfikować. Domyślnie do strony startowej mapowana jest ścieżka pusta, więc nie jest konieczne dodawanie do adresu komputera dodatkowych ścieżek.

\begin{figure}[!h]
	\includegraphics{figures/www-start.png}
	\caption{Przykładowe okno startowe strony.}
	\label{fig:etap3-www-start}
\end{figure}


Rysunek~\ref{fig:etap3-www-start} pokazuje przykładowy, startowy obraz strony widziany w~przeglądarce internetowej. W~widoczne pola należy wprowadzić pożądane wartości. Gdy zostaną one odpowiednio ustawione, użytkownik może przycisnąć przycisk ,,Wyszukaj'', który spowoduje wyświetlenie znalezionych przez system tras. Jednak do czasu uzyskania odpowiedzi z~serwera, w~miejsce przyszłych wyników wyświetlana jest informacja o tym, że zapytanie jest obecnie przetwarzane.

\begin{figure}[!htp]
	\includegraphics{figures/www-calendar.png}
	\caption{Pokazany interaktywny kalendarz w działaniu.}
	\label{fig:etap3-www-calendar}
	
	\vspace{1cm}
	
	\includegraphics{figures/www-result.png}
	\caption{Przykładowy wynik zapytania.}
	\label{fig:etap3-www-result}
\end{figure}

Przy próbie zmiany pola daty, użytkownikowi pojawi się interaktywny kalendarz służący do wyboru daty. Obraz~\ref{fig:etap3-www-calendar} przedstawia przykładowy widok uwzględniający wspomniany kalendarz. Wybranie (tj. kliknięcie) żądanego dnia powoduje automatyczne wpisanie do pola tekstowego wartości daty tego dnia.

Rysunek~\ref{fig:etap3-www-result} pokazuje gotowy wynik zapytania po wciśnięciu przycisku ,,Wyszukaj''. Ukazywane są trzy najlepsze połączenia. Każde połączenie rozpoczyna się od wyróżnionego nagłówka. Następnie widoczne są kolejne połączenia wraz z nazwami przystanków oraz czasami startu i końca każdego połączenia.


\section{Działanie aplikacji}
Rysunek~\ref{fig:etap3-architektura} przedstawia budowę oraz działanie aplikacji. Interfejs użytkownika reprezentowany jest przez stronę www. W~modelu MVC (\textit{model}, \textit{view}, \textit{controller}) zapytanie pobierające stronę trafiłoby do kontrolera, który wykonałby operację na bazie danych i~w~efekcie zwrócił stronę z wynikiem tych operacji. W~naszym przypadku jest trochę inaczej. Strona www w gruncie rzeczy pełni rolę statycznego klienta, dlatego też serwowana jest z pominięciem kontrolera dzięki dodaniu linii \texttt{<mvc:view-controller path="/" view-name="/staticViews/static"/>} w~konfiguracji servletu. Prawdziwy mechanizm MVC ukryty jest niżej: w~zapytaniu XMLHttpRequest. Formularz na stronie wysyłany jest asynchronicznie do kontrolera, którego uproszczony kod pokazany jest na rysunku~\ref{fig:etap3-kontr}.

\begin{figure}[!ht]
	\includegraphics{figures/controller.jpg}
	\caption{Skrócony kod kontrolera.}
	\label{fig:etap3-kontr}
\end{figure}

Warto zwrócić uwagę na kilka szczegółów. Zachowanie elementów klasy jest mocno zmodyfikowane przez annotacje.

Przykładowo {\it @Autowired} wstrzykuje podczas tworzenia tej klasy instancję obiektu oznaczonego przez adnotację (oczywiście klasa tego obiektu musi być specjalnie oznaczona np. jako {\it @Controller} lub {\it @Service}). Sama definicja metody zawiera dwie annotacje: {\it @RequestMapping} zawiera instrukcje dotyczące mapowania adresów URL na tę metodę (w~tym przypadku \texttt{/rest/findConnections} i~np.~\texttt{http://localhost/travelFinder/rest/findConnections?starting_point=Tczew\&destination=Skowarcz\&starting_date=2012-06-12+00\%3A05}) oraz {\it @ResponseBody}, która mówi, że wartość zwrócona przez funkcję zostanie wysłana bezpośrednio jako zawartość odpowiedzi. Mechanizmy frameworku Spring MVC zadbają o~automatyczną konwersję obiektów typu List oraz Map na obiekty notacji javascript (JSON). Przykładowa odpowiedź przedstawiona jest na obrazie~\ref{fig:etap3-www-json}. Ciało funkcji kontrolera zawiera trzy odwołania do bazy danych: dwa szukające w~niej przystanków za pomocą tzw.~repozytoriów (interfejsy do przeszukiwań bazy udostępnione przez Neo4j) oraz jedno korzystające z~algorytmu utworzonego przez zespół projektowy i~zaimplementowanego w~serwisie przez.

Ze względu na swoją asynchroniczność, po zleceniu wyszukania połączenia, rejestrowana jest funkcja zwrotna, która przetwarza zwrócone dane (JSON) i~generuje dynamicznie odpowiednie elementy strony.

\begin{figure}[!ht]
	\includegraphics{figures/json.jpg}
	\caption{Przykład odpowiedzi JSON.}
	\label{fig:etap3-www-json}
\end{figure}


\section{Algorytm wyszukiwania połączeń}
Algorytm wyszukuje połączenia o najkrótszym czasie pomiędzy datą początkową, a~datą zakończenia podróży. Jako parametry algorytmu ustawić można maksymalną liczbę przesiadek, maksymalny czas oczekiwania na kolejne połączenie oraz liczbę proponowanych połączeń. 
Aby zapewnić wystarczającą wydajność wyznaczania połączeń wprowadzone zostało ograniczenie na głębokość przeszukiwania grafu połączeń w głąb. Wybrana wartość wyniosła 45 - oznacza to, że najdłuższe znalezione połączenie może mieć maksymalnie 45 stacji pośrednich. Została ona wyznaczona po przeprowadzeniu testów, mierzących średni czas odpowiedzi algorytmu, mających ustalić maksymalną wartość parametru przy zachowaniu odpowiedniej wydajności. Dla podanej wartości średni czas wykonania algorytmu dla zapytania wynosił około 50ms. W przypadku wdrażania aplikacji na wydajnieszym serwerze wartość parametru powinna być dostosowana do możliwości obliczeniowych serwera.
Za pracę algorytmu odpowiada następująca metoda serwisu:
\begin{lstlisting}[style=snippet]
public Iterable<Path> findShortestConnection(Date starting_date, Place start, Place end, int max_liczba_przesiadek, int ile_polaczen);
\end{lstlisting}

Parametry z~powyższego fragmentu kodu mają następujące znaczenie:
\begin{itemize}
	\item \textit{starting_date} -- data rozpoczęcia podróży,
	\item \textit{start} -- stacja początkowa,
	\item \textit{end} -- stacja końcowa,
	\item \textit{max_liczba_przesiadek} -- maksymalna dozwolona liczba przesiadek,
	\item \textit{ile_polaczen} -- liczba proponowanych połączeń,
	\item zwracana wartość -- struktura zawierająca zbiór ścieżek w grafie.
\end{itemize}

Algorytm składa się z~dwóch etapów: wyznaczania możliwych połączeń między stacjami oraz wybierania najkrótszych połączeń.

\subsection{Wyznaczanie możliwych połączeń pomiędzy stacjami}
Aby wyznaczyć możliwe połączenia pomiędzy dwoma wybranymi stacjami zastosowany został algorytm poszukiwania ścieżek prostych pomiędzy węzłami w~grafie, znajdujący się w~klasie \textit{GraphAlgoFactory}, będącej częścią neo4j. W~celu przyśpieszenia wyszukiwania i~minimalizacji liczby zwracanych ścieżek przez ten etap, zdefiniowana została struktura mająca na celu eliminację połączeń nieaktywnych: takich, które nie kursują w~dniu, dla którego poszukujemy połączenia.

\subsection{Wybranie najkrótszych połączeń}
Następnym krokiem jest wybranie zdefiniowanej wcześniej liczby połączeń o~najmniejszym czasie trwania. W~tym celu dla każdego połączenia otrzymanego w~pierwszym etapie algorytmu obliczamy jego czas trwania. Jest to czas pomiędzy datą podaną jako parametr algorytmu, a~czasem zakończenia ostatniego etapu połączenia. W algorytmie uwzględniony w ten sposób został czas trwania połączeń oraz czas oczekiwania na połączenia bądź przesiadki. Po wyliczeniu czasów trwania połączeń wybieramy te o~najmniejszym czasie trwania. Liczba wybranych połączeń zależna jest od ustawionego parametru.
 
\section{Baza danych}
Spring Data Neo4j zawiera wbudowaną bazę neo4j. W bazie przechowywane będą obiekty specjalnie wyznaczonych klas, tzw. klas domenowych. Framework udostępnia dwie metody opisu klas domenowych. Pierwsza, użyta w projekcie to Simple Object Graph Mapping oparta o annotacje, druga bardziej zaawansowana Advanced Mapping with AspectJ wykorzystuje aspekty.

\subsection{Klasy domenowe}
Graf przechowuje w wierzchołkach informację o miastach. Odpowiada za to klasa {\it com.travelFinder.domain.Place}
\begin{lstlisting}[style=snippet]
@NodeEntity
public class Place {

    @GraphId
    Long id;
    
    @Indexed  
    String name;
    
    @RelatedToVia(type="CONNECTION_TO",elementClass=Connection.class,direction=Direction.OUTGOING)
    Set<Connection> connections;
}
\end{lstlisting}

Użyte annotacje:
\begin{itemize}
\item {\it @NodeEntity} oznacza iż klasa reprezentuje wierzchołek grafu
\item {\it @GraphId} oznacza pole będące wewnetrznym id obiektu
\item {\it @Indexed} oznacza iż pole będzie indeksowane
\item {\it @RelatedToVia} opisuje połączenia wierzchołka z innymi
\end{itemize}
Na szczególną uwagę zasługuje annotacja @RelatedToVia, jest to rozbudowana wersja annotacji @RelatedTo. Wersja prosta pozwala jedynie na zaznaczenie relacji miedzy wierzchołkami, wersja rozbudowana pozwala na wprowadzenie dodatkowych danych przechowywanych w krawędzi. Klasę opisującą krawędź określa parametr {\it elementClass}.

Klasa określająca krawędź jest annotowana {\it @RelationshipEntity}.
\begin{lstlisting}[style=snippet]
@RelationshipEntity(type = "CONNECTION_TO")
public class Connection {

    @GraphId
    Long id;
    @StartNode
    Place start;
    @EndNode
    Place end;
    private String connectionId;
    private String company;
    private ConnectionType type;
    private Date startDate;
    private Date endDate;
    private OffDays offdays;
    private Weekdays weekdaysActive;
\end{lstlisting}

Użyte annotacje
\begin{itemize}
\item {\it @StartNode} pole przechowujące wierzchołek początkowy
\item {\it @EndNode} pole przechowujące wierzchołek końcowy
\end{itemize}

W ten sposób przy pomocy annotacji można szybko stworzyć klasy gotowe do przechowywania w bazie danych.

\subsection{Repozytoria}
Dostęp do danych w bazie uzyskujemy przy pomocy repozytoriów. W projekcie występują dwa {\it ConnectionRepository} i {\it PlaceRepository}. 
\begin{lstlisting}[style=snippet]
public interface ConnectionRepository extends GraphRepository<Connection>, NamedIndexRepository<Connection> {	
}

public interface PlaceRepository extends GraphRepository<Place>, NamedIndexRepository<Place> {
}

\end{lstlisting}
Jak widać ich utworzenie jest bardzo proste. Ich połączenie z pozostałą częścią projektu następuje przy użyciu pól z annotacją {\it @Autowired}. Główne metody repozytorium to różne wyszukiania, usuwania i zapisywanie nowych obiektów.

\subsection{ETL jako przykład usługi korzystajacej z bazy danych}
W ramach projektu powstała usługa ETL (Extract,~Transform,~Load[Pobierz,~Przetwórz,~Załaduj]) {\it DbPopulator}. Określenie usługa wynika z annotowania klasy {\it @Service}. Zadaniem klasy jest stworzenie bazy danych, z podanej listy plików CSV.

\begin{lstlisting}[style=snippet]
@Service
public class DbPopulator {

    @Autowired
    PlaceRepository placeRepository;
    @Autowired
    ConnectionRepository connectionRepository;    
\end{lstlisting}
Wykorzystywane są zdefiniowane uprzednio repozytoria, przyczym ich obiekty nie są tworzone ręcznie, wszystko załatwia annotacja {\it @Autowired}. Pozostały fragment to odczyt pliku, konwersja danych oraz dodanie obiektu do bazy.
\begin{lstlisting}[style=snippet]
            Place startPlace = placeRepository.findByPropertyValue("name", start);
            if (startPlace == null) {
                startPlace = new Place(start);
                placeRepository.save(startPlace);
                startPlace = placeRepository.findByPropertyValue("name", start);
            }
\end{lstlisting}
Powyższy listing obrazuje wyszukiwanie w bazie danych pola według nazwy. Jeśli obiekt nie został znaleziony następuje jego utworzenie i zapis w repozytorium/bazie danych. Ponowny odczyt jest związany z koniecznością utworzenia obiektów dodatkowych, takich jak zbiór przechowujacy połączenia.